package gonet

import (
	"fmt"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/pack"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/request"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/route"
	"github.com/panjf2000/gnet/v2"
	bbPool "github.com/panjf2000/gnet/v2/pkg/pool/bytebuffer"
	goPool "github.com/panjf2000/gnet/v2/pkg/pool/goroutine"
	"time"
)

type UdpServer struct {
	pool *goPool.Pool
	//FrameDecoder decoder.FrameDecoder
	apis          map[uint32]route.IRouter
	connStart     func(c gnet.Conn)            // 客户端建立连接时执行的方法
	connStop      func(c gnet.Conn)            // 客户端断开连接时执行的方法
	connIntercept func(request.IRequest) error // 请求拦截时执行的方法
}

// OnBoot 当引擎准备好接受连接时，将触发。
// //参数引擎具有信息和各种实用程序。
func (us *UdpServer) OnBoot(eng gnet.Engine) (action gnet.Action) {
	fmt.Println("OnBoot")
	return
}

// OnShutdown 当发动机关闭时发生火灾，它在
// 所有事件循环和连接都关闭。
func (us *UdpServer) OnShutdown(eng gnet.Engine) {
	fmt.Println("OnShutdown")
}

// OnOpen 在打开新连接时激发。
//
// Conn c具有有关连接的信息，例如其本地和远程地址。
// 参数out是将要发送回对等方的返回值。
// 通常不建议在OnOpen中将大量数据发送回对等端。
func (us *UdpServer) OnOpen(c gnet.Conn) (out []byte, action gnet.Action) {
	//c.SetContext(decoder.NewFrameDecoder())
	fmt.Println("OnOpen")
	if us.connStart != nil {
		us.connStart(c)
	}

	return
}

// OnClose 当连接关闭时激发。
// 参数err是最后一个已知的连接错误。
func (us *UdpServer) OnClose(c gnet.Conn, err error) (action gnet.Action) {
	fmt.Println("OnClose")
	if us.connStop != nil {
		us.connStop(c)
	}
	return
}

// OnTraffic 套接字从对等端接收数据时激发。
//
// 注意，从Conn.Peek（int）/Conn.Next（int）返回的[]字节不允许传递到新的goroutine，
// 因为在OnTraffic（）返回后，这个[]字节将在事件循环中重复使用。
// 如果必须在新的goroutine中使用这个[]字节，则应该复制它或调用Conn.Read（[]字节）
// 要将数据读取到您自己的[]字节中，请将新的[]字节传递给新的goroutine。
func (us *UdpServer) OnTraffic(c gnet.Conn) (action gnet.Action) {
	buf := bbPool.Get()
	_, _ = c.WriteTo(buf)
	_ = us.pool.Submit(func() {
		//fmt.Println("UDP字节码：", buf.Bytes())
		message := pack.NewMessage(buf.Bytes(), pack.UDP)
		if message == nil {
			//  数据不完整
			_ = c.Close()
			return
		}
		if message.GetUserId() == 0 {
			fmt.Println("非法链接,未找到用户信息：", message.GetMsgId())
			_ = c.Close()
			return
		}
		iRequest, cancel := request.NewRequest(c, message)
		defer cancel()
		if us.connIntercept != nil {
			err := us.connIntercept(iRequest)
			if err != nil {
				//_ = response.Error(c, err)
				_ = c.Close()
				return
			}
		}
		// 找到指定路由
		router, ok := us.apis[message.GetMsgId()]
		if !ok {
			// 404
			fmt.Println("未找到路由：", message.GetMsgId())
			//_ = iRequest.Send(uint32(cmd.CMD_S_Err), &message2.S_Err{
			//	Code:    404,
			//	Message: "未找到路由",
			//})
			//_ = response.ErrorNotRoute(c)
			_ = c.Close()
			//_ = iRequest.Send(4, []byte("404"))
			return
		}
		router.PreHandle(iRequest)
		router.Handle(iRequest)
		router.PostHandle(iRequest)
	})

	return
}

// OnTick 发动机启动后立即点火，并将再次点火
// 在延迟返回值指定的持续时间之后。
func (us *UdpServer) OnTick() (delay time.Duration, action gnet.Action) {
	//fmt.Println("OnTick")
	delay = time.Second * 10
	//action = gnet.Shutdown
	return
}
